## Инициализатор `__init__` и финализатор `__del__`


### 3. Объявите три класса геометрических фигур: Line, Rect, Ellipse. Должна быть возможность создавать объекты каждого класса следующими командами:

```python
g1 = Line(a, b, c, d)
g2 = Rect(a, b, c, d)
g3 = Ellipse(a, b, c, d)
```

Здесь в качестве аргументов `a, b, c, d` передаются координаты верхнего правого и нижнего левого углов (произвольные числа). В каждом объекте координаты должны сохраняться в локальных свойствах sp (верхний правый угол) и ep (нижний левый) в виде кортежей `(a, b)` и `(c, d)` соответственно.

Сформируйте 217 объектов этих классов: для каждого текущего объекта класс выбирается случайно (или Line, или Rect, или Ellipse). Координаты также генерируются случайным образом (числовые значения). Все объекты сохраните в списке elements.

В списке `elements` обнулите координаты объектов только для класса `Line`.


<details>
<summary>Подсказка</summary>

```python
from random import randint, choice


class Figure:
    def __init__(self, a, b, c, d) -> None:
        self.sp = (a, b)
        self.ep = (c, d)


class Line(Figure):
    ...


class Rect(Figure):
    ...


class Ellipse(Figure):
    ...


lst_cls = [Line, Rect, Ellipse]
f = lambda: randint(0, 10)


elements = [choice(lst_cls)(f(), f(), f(), f()) for _ in range(217)]

for i in range(len(elements)):
    if isinstance(elements[i], Line):
        elements[i].sp, elements[i].ep = (0, 0), (0, 0)
```
</details>


### 4. Объявите класс TriangleChecker, объекты которого можно было бы создавать командой:

```python
tr = TriangleChecker(a, b, c)
```
Здесь a, b, c - длины сторон треугольника.

В классе TriangleChecker необходимо объявить метод is_triangle(), который бы возвращал следующие коды:

1 - если хотя бы одна сторона не число (не float или int) или хотя бы одно число меньше или равно нулю;
2 - указанные числа a, b, c не могут являться длинами сторон треугольника;
3 - стороны a, b, c образуют треугольник.

Проверку параметров a, b, c проводить именно в таком порядке.

Прочитайте из входного потока строку, содержащую три числа, разделенных пробелами, командой:

```python
a, b, c = map(int, input().split())
```
Затем, создайте объект tr класса TriangleChecker и передайте ему прочитанные значения a, b, c. Вызовите метод is_triangle() из объекта tr и выведите результат на экран (код, который она вернет).


<details>
<summary>Подсказка</summary>

```python
class TriangleChecker:
    def __init__(self, a, b, c):
        self.lst = (a, b, c)
       
    def is_triangle(self):
        for num in self.lst:
            if not isinstance(num, (int, float)) or num <= 0 or isinstance(num, bool):
                return 1 
        if max(self.lst) >= sum(self.lst) - max(self.lst):
            return 2
        return 3
        

# a,b,c = 3.0,4,True
a, b, c = map(int, input().split())
tr = TriangleChecker(a, b, c)
print(tr.is_triangle())
```
</details>

### 5. Объявите в программе следующие несколько классов:
```
CPU - класс для описания процессоров;
Memory - класс для описания памяти;
MotherBoard - класс для описания материнских плат.
```
Обеспечить возможность создания объектов каждого класса командами:
```
cpu = CPU(наименование, тактовая частота)
mem = Memory(наименование, размер памяти)
mb = MotherBoard(наименование, процессор, память1, память2, ..., памятьN)
```
Обратите внимание при создании объекта класса MotherBoard можно передавать несколько объектов класса Memory, максимум N - по числу слотов памяти на материнской плате (N = 4).

Объекты классов должны иметь следующие локальные свойства: 

* для класса CPU: name - наименование; fr - тактовая частота;
* для класса Memory: name - наименование; volume - объем памяти;
* для класса MotherBoard: name - наименование; cpu - ссылка на объект класса CPU; total_mem_slots = 4 - общее число слотов памяти (атрибут прописывается с этим значением и не меняется); mem_slots - список из объектов класса Memory (максимум total_mem_slots = 4 штук по максимальному числу слотов памяти).


Класс `MotherBoard` должен иметь метод `get_config(self)` для возвращения текущей конфигурации компонентов на материнской плате в виде следующего списка из четырех строк:
```
['Материнская плата: <наименование>',
'Центральный процессор: <наименование>, <тактовая частота>',
'Слотов памяти: <общее число слотов памяти>',
'Память: <наименование_1> - <объем_1>; <наименование_2> - <объем_2>; ...; <наименование_N> - <объем_N>']
```

Создайте объект `mb` класса `MotherBoard` с одним `CPU` (объект класса CPU) и двумя слотами памяти (объекты класса Memory).

<details>
<summary>Подсказка</summary>

```python
class CPU:
    def __init__(self, name, fr):
        self.name = name
        self.fr = fr
class Memory:
    def __init__(self,name, volume):
        self.name = name
        self.volume = volume

class MotherBoard:
    def __init__(self, name, cpu, mem_slots, total_mem_slots = 4):
        self.name = name
        self.cpu = cpu
        self.mem_slots = mem_slots[:total_mem_slots]
        self.total_mem_slots = total_mem_slots       

    def get_config(self):
        a = []
        a.append(f'Материнская плата: {self.name}')
        a.append(f"Центральный процессор: {self.cpu.name}, {self.cpu.fr}")
        a.append(f'Слотов памяти: {self.total_mem_slots}')
        a.append(f"Память: {'; '.join([f'{i.name} - {i.volume}' for i in self.mem_slots])}")
        return a

cpu = CPU('i5', 3000)
mem1, mem2 = Memory('Kingstone', 2000), Memory('Samsung', 2600)
    
mb = MotherBoard('Asus', cpu, [mem1, mem2])

```
</details>


### 6.  Объявите в программе класс Cart (корзина), объекты которого создаются командой:
```
cart = Cart()
```
Каждый объект класса `Cart` должен иметь локальное свойство goods - список объектов для покупки (объекты классов `Table, TV, Notebook и Cup`). 

Изначально этот список должен быть пустым.

В классе `Cart` объявить методы:
```
add(self, gd) - добавление в корзину товара, представленного объектом gd;
remove(self, indx) - удаление из корзины товара по индексу indx;
get_list(self) - получение из корзины товаров в виде списка из строк:
```
```
['<наименовние_1>: <цена_1>',
'<наименовние_2>: <цена_2>',
...
'<наименовние_N>: <цена_N>']
```

Объявите в программе следующие классы для описания товаров:
```
Table - столы;
TV - телевизоры;
Notebook - ноутбуки;
Cup - кружки.
```
Объекты этих классов должны создаваться командой:
```
gd = ИмяКласса(name, price)
```
Каждый объект классов товаров должен содержать локальные свойства:
```
name - наименование;
price - цена.
```
Создайте в программе объект `cart` класса `Cart`. Добавьте в него два телевизора `(TV)`, один стол `(Table)`, два ноутбука `(Notebook)` и одну кружку `(Cup)`. Названия и цены придумайте сами. 


<details>
<summary>Подсказка</summary>

```python
class Cart:
    def __init__(self):
        self.goods = []

    def add(self, gd):
        self.goods.append(gd)

    def remove(self, indx):
        del self.goods[indx]

    def get_list(self):
        return [f'{i.name}: {i.price}' for i in self.goods]       

class Table:
    def __init__(self, name, price):
        self.name = name
        self.price = price


class TV:
    def __init__(self, name, price):
        self.name = name
        self.price = price


class Notebook:
    def __init__(self, name, price):
        self.name = name
        self.price = price


class Cup:
    def __init__(self, name, price):
        self.name = name
        self.price = price


cart = Cart()

tv1 = TV('LG', 100)
tv2 = TV('Samsung', 200)

tbl1 = Table('Фанерник', 10)
ntb1 = Notebook('MAC', 130)
ntb2 = Notebook('Asus', 90)
cup = Cup('Glass', 3)

cart.add(tv1)
cart.add(tv2)
cart.add(tbl1)
cart.add(ntb1)
cart.add(ntb2)
cart.add(cup)

cart.get_list()

```
</details>


### 7. Необходимо реализовать односвязный список (не список языка Python, объекты в списке не хранить, а формировать связанную структуру, показанную на рисунке) из объектов класса ListObject:

![](img/linked-list.png)

Для этого объявите в программе класс `ListObject`, объекты которого создаются командой:
```
obj = ListObject(data)
```
Каждый объект класса ListObject должен содержать локальные свойства:

next_obj - ссылка на следующий присоединенный объект (если следующего объекта нет, то next_obj = None);
data - данные объекта в виде строки.

В самом классе ListObject должен быть объявлен метод:

link(self, obj) - для присоединения объекта obj такого же класса к текущему объекту self (то есть, атрибут next_obj объекта self должен ссылаться на obj).

Прочитайте список строк из входного потока командой:
```
lst_in = list(map(str.strip, sys.stdin.readlines()))
```
Затем сформируйте односвязный список, в объектах которых (в атрибуте data) хранятся строки из списка lst_in (первая строка в первом объекте, вторая - во втором и  т.д.).

На первый добавленный объект класса ListObject должна ссылаться переменная head_obj.

<summary>Подсказка</summary>

```python
import sys

class ListObject:
    def __init__(self, data):
        self.data = data
        self.next_obj = None   

    def link(self, obj):
        self.next_obj = obj



lst_in = list(map(str.strip, sys.stdin.readlines()))

head_obj = ListObject(lst_in[0])
obj = head_obj
for i in range(1, len(lst_in)):
    obj_new = ListObject(lst_in[i])
    obj.link(obj_new)
    obj = obj_new 


```
</details>